home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2002 #3
/
Amiga Plus CD - 2002 - No. 03.iso
/
AmiSoft
/
Hard
/
Drivr
/
3c589.lha
/
3c589
/
Source
/
unit.c
< prev
Wrap
C/C++ Source or Header
|
2003-02-08
|
46KB
|
2,178 lines
/*
File: unit.c
Author: Neil Cafferkey
Copyright (C) 2001-2003 Neil Cafferkey
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
*/
#include <exec/memory.h>
#include <exec/execbase.h>
#include <exec/errors.h>
#include <proto/exec.h>
#include <proto/alib.h>
#include <proto/cardres.h>
#include <proto/utility.h>
#include <proto/pccard.h>
#include <proto/timer.h>
#include "device.h"
#include "etherlink3.h"
#include "unit_protos.h"
#include "request_protos.h"
#define TASK_PRIORITY 0
#define STACK_SIZE 4096
#define MAX_TUPLE_SIZE 0xff
#define TUPLE_BUFFER_SIZE (MAX_TUPLE_SIZE+8)
#define INT_MASK\
(EL3INTF_RXCOMPLETE|EL3INTF_TXAVAIL|EL3INTF_TXCOMPLETE|EL3INTF_FAILURE)
IMPORT struct ExecBase *AbsExecBase;
static BOOL InitialiseCard(struct DevUnit *unit,struct DevBase *base);
static VOID InitialiseAdapter(struct DevUnit *unit,struct DevBase *base);
static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
ULONG lower_bound_left,UWORD lower_bound_right,ULONG upper_bound_left,
UWORD upper_bound_right,struct DevBase *base);
static VOID CardRemovedInt(struct DevUnit *unit REG("a1"));
static VOID CardInsertedInt(struct DevUnit *unit REG("a1"));
static UBYTE CardStatusInt(UBYTE mask REG("d0"),
struct DevUnit *unit REG("a1"));
static VOID RxInt(struct DevUnit *unit REG("a1"));
static VOID CopyPacket(struct DevUnit *unit,struct IOSana2Req *request,
UWORD packet_size,UWORD packet_type,BOOL all_read,struct DevBase *base);
static BOOL AddressFilter(struct DevUnit *unit,UBYTE *address,
struct DevBase *base);
static VOID TxInt(struct DevUnit *unit REG("a1"));
static VOID TxError(struct DevUnit *unit,struct DevBase *base);
static VOID ReportEvents(struct DevUnit *unit,ULONG events,
struct DevBase *base);
static VOID UnitTask();
static UWORD ReadEEPROM(volatile UBYTE *io_base,UWORD index);
static UWORD LEWordIn(volatile UBYTE *address);
/****i* 3c589.device/GetUnit ***********************************************
*
* NAME
* GetUnit -- Get a unit by number.
*
* SYNOPSIS
* unit = GetUnit(unit_num)
*
* struct DevUnit *GetUnit(ULONG);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
struct DevUnit *GetUnit(ULONG unit_num,struct DevBase *base)
{
struct DevUnit *unit;
unit=FindUnit(unit_num,base);
if(unit==NULL)
{
unit=CreateUnit(unit_num,base);
if(unit!=NULL)
AddTail((APTR)&base->units,(APTR)unit);
}
return unit;
}
/****i* 3c589.device/FindUnit **********************************************
*
* NAME
* FindUnit -- Find a unit by number.
*
* SYNOPSIS
* unit = FindUnit(unit_num)
*
* struct DevUnit *FindUnit(ULONG);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
struct DevUnit *FindUnit(ULONG unit_num,struct DevBase *base)
{
struct DevUnit *unit,*tail;
BOOL found;
unit=(APTR)base->units.mlh_Head;
tail=(APTR)&base->units.mlh_Tail;
found=FALSE;
while((unit!=tail)&&!found)
{
if(unit->unit_num==unit_num)
found=TRUE;
else
unit=(APTR)unit->node.mln_Succ;
}
if(!found)
unit=NULL;
return unit;
}
/****i* 3c589.device/CreateUnit ********************************************
*
* NAME
* CreateUnit -- Create a unit.
*
* SYNOPSIS
* unit = CreateUnit(unit_num)
*
* struct DevUnit *CreateUnit(ULONG);
*
* FUNCTION
* Creates a new unit.
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
struct DevUnit *CreateUnit(ULONG unit_num,struct DevBase *base)
{
BOOL success=TRUE;
struct DevUnit *unit;
struct Task *task;
struct MsgPort *port;
UBYTE i;
struct CardHandle *card_handle;
APTR stack;
struct Interrupt *card_removed_int,*card_inserted_int,*card_status_int;
unit=AllocMem(sizeof(struct DevUnit),MEMF_CLEAR);
if(unit==NULL)
success=FALSE;
if(success)
{
unit->unit_num=unit_num;
unit->device=base;
InitSemaphore(&unit->access_lock);
/* Set up packet filter command */
unit->rx_filter_cmd=EL3CMD_SETRXFILTER|EL3CMD_SETRXFILTERF_BCAST
|EL3CMD_SETRXFILTERF_UCAST;
/* Create the message ports for queuing requests */
for(i=0;i<REQUEST_QUEUE_COUNT;i++)
{
unit->request_ports[i]=port=AllocMem(sizeof(struct MsgPort),
MEMF_PUBLIC|MEMF_CLEAR);
if(port==NULL)
success=FALSE;
if(success)
{
NewList(&port->mp_MsgList);
port->mp_Flags=PA_IGNORE;
port->mp_SigTask=&unit->tx_int;
}
}
card_handle=unit->card_handle=
AllocMem(sizeof(struct CardHandle),MEMF_PUBLIC|MEMF_CLEAR);
unit->tuple_buffer=
AllocVec(TUPLE_BUFFER_SIZE,MEMF_ANY);
unit->rx_buffer=AllocVec((MAX_PACKET_SIZE+3)&~3,MEMF_PUBLIC);
unit->tx_buffer=AllocVec(MAX_PACKET_SIZE,MEMF_PUBLIC);
if((card_handle==NULL)||(unit->tuple_buffer==NULL)||
(unit->rx_buffer==NULL)||(unit->tx_buffer==NULL))
success=FALSE;
}
if(success)
{
NewList((APTR)&unit->openers);
NewList((APTR)&unit->type_trackers);
NewList((APTR)&unit->multicast_ranges);
/* Initialise transmit and receive interrupts */
unit->rx_int.is_Node.ln_Name=(TEXT *)device_name;
unit->rx_int.is_Node.ln_Pri=16;
unit->rx_int.is_Code=RxInt;
unit->rx_int.is_Data=unit;
unit->tx_int.is_Node.ln_Name=(TEXT *)device_name;
unit->tx_int.is_Code=TxInt;
unit->tx_int.is_Data=unit;
unit->request_ports[WRITE_QUEUE]->mp_Flags=PA_SOFTINT;
}
if(success)
{
/* Set up card handle */
card_handle->cah_CardNode.ln_Pri=HANDLE_PRIORITY;
card_handle->cah_CardNode.ln_Name=(APTR)device_name;
card_handle->cah_CardFlags=CARDF_IFAVAILABLE;
card_handle->cah_CardRemoved=card_removed_int=
AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR);
card_handle->cah_CardInserted=card_inserted_int=
AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR);
card_handle->cah_CardStatus=card_status_int=
AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR);
if((card_removed_int==NULL)
||(card_inserted_int==NULL)
||(card_status_int==NULL))
success=FALSE;
}
if(success)
{
/* Try to gain access to card */
card_removed_int->is_Code=CardRemovedInt;
card_removed_int->is_Data=unit;
card_inserted_int->is_Code=CardInsertedInt;
card_inserted_int->is_Data=unit;
card_status_int->is_Code=(APTR)CardStatusInt;
card_status_int->is_Data=unit;
if(OwnCard(card_handle)!=0)
success=FALSE;
}
if(success)
{
unit->flags|=UNITF_HAVECARD;
if(!InitialiseCard(unit,base))
success=FALSE;
/* Create a new task */
unit->task=task=AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
if(task==NULL)
success=FALSE;
}
if(success)
{
stack=AllocMem(STACK_SIZE,MEMF_PUBLIC);
if(stack==NULL)
success=FALSE;
}
if(success)
{
/* Initialise and start task */
task->tc_Node.ln_Type=NT_TASK;
task->tc_Node.ln_Pri=TASK_PRIORITY;
task->tc_Node.ln_Name=(APTR)device_name;
task->tc_SPUpper=stack+STACK_SIZE;
task->tc_SPLower=stack;
task->tc_SPReg=stack+STACK_SIZE;
if(AddTask(task,UnitTask,NULL)==NULL)
success=FALSE;
}
/* Send the unit to the new task */
if(success)
task->tc_UserData=unit;
if(!success)
{
DeleteUnit(unit,base);
unit=NULL;
}
return unit;
}
/****i* 3c589.device/DeleteUnit ********************************************
*
* NAME
* DeleteUnit -- Delete a unit.
*
* SYNOPSIS
* DeleteUnit(unit)
*
* VOID DeleteUnit(struct DevUnit *);
*
* FUNCTION
* Deletes a unit.
*
* INPUTS
* unit - Device unit (can be NULL).
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
VOID DeleteUnit(struct DevUnit *unit,struct DevBase *base)
{
UBYTE i;
struct CardHandle *card_handle;
struct Task *task;
if(unit!=NULL)
{
task=unit->task;
if(task!=NULL)
{
if(task->tc_SPLower!=NULL)
{
RemTask(task);
FreeMem(task->tc_SPLower,STACK_SIZE);
}
FreeMem(task,sizeof(struct Task));
}
for(i=0;i<REQUEST_QUEUE_COUNT;i++)
{
if(unit->request_ports[i]!=NULL)
FreeMem(unit->request_ports[i],sizeof(struct MsgPort));
}
FreeVec(unit->tuple_buffer);
card_handle=unit->card_handle;
if(card_handle!=NULL)
{
if((unit->flags&UNITF_HAVECARD)!=0)
{
if((unit->flags&UNITF_HAVEADAPTER)!=0)
GoOffline(unit,base);
CardMiscControl(card_handle,0);
CardResetCard(card_handle);
ReleaseCard(card_handle,CARDF_REMOVEHANDLE);
}
FreeVec(card_handle->cah_CardStatus);
FreeVec(card_handle->cah_CardInserted);
FreeVec(card_handle->cah_CardRemoved);
FreeMem(card_handle,sizeof(struct CardHandle));
}
FreeVec(unit->tx_buffer);
FreeVec(unit->rx_buffer);
FreeMem(unit,sizeof(struct DevUnit));
}
return;
}
/****i* 3c589.device/InitialiseCard ****************************************
*
* NAME
* InitialiseCard -- .
*
* SYNOPSIS
* success = InitialiseCard(unit)
*
* BOOL InitialiseCard(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit
*
* RESULT
* success
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static BOOL InitialiseCard(struct DevUnit *unit,struct DevBase *base)
{
BOOL success=TRUE;
struct CardMemoryMap *card_map;
struct CardHandle *card_handle;
UBYTE config_value,i,window_count,*tuple_buffer;
const struct TagItem *tuple_tags=NULL;
ULONG *io_bases,*io_lengths,io_base=0,config_base_offset;
UWORD maker,product;
/* Wake up card */
card_handle=unit->card_handle;
CardMiscControl(card_handle,CARD_ENABLEF_DIGAUDIO|CARD_DISABLEF_WP);
/* Get card's make and model */
tuple_buffer=unit->tuple_buffer;
if(CopyTuple(card_handle,tuple_buffer,PCCARD_TPL_MANFID,MAX_TUPLE_SIZE))
{
tuple_tags=PCCard_GetTupleInfo(tuple_buffer);
if(tuple_tags!=NULL)
{
maker=GetTagData(PCCARD_Maker,0,tuple_tags);
product=GetTagData(PCCARD_Product,0,tuple_tags);
}
}
/* Check this is a card we can use */
if((tuple_tags==NULL)||!((maker==0x101)&&((product==0x35)||
(product==0x3d)||(product==0x562)||(product==0x589))))
success=FALSE;
/* Get configuration data */
if(!CopyTuple(card_handle,tuple_buffer,PCCARD_TPL_CONFIG,MAX_TUPLE_SIZE))
success=FALSE;
if(success)
{
tuple_tags=PCCard_GetTupleInfo(tuple_buffer);
if(tuple_tags==NULL)
success=FALSE;
}
if(success)
{
config_base_offset=GetTagData(PCCARD_RegisterBase,0,tuple_tags);
PCCard_FreeTupleInfo(tuple_tags);
tuple_tags=NULL;
/* Get IO base */
if(!CopyTuple(card_handle,tuple_buffer,PCCARD_TPL_CFTABLEENTRY,
MAX_TUPLE_SIZE))
success=FALSE;
}
if(success)
{
tuple_tags=PCCard_GetTupleInfo(tuple_buffer);
if(tuple_tags==NULL)
success=FALSE;
}
if(success)
{
config_value=GetTagData(PCCARD_ModeNo,0,tuple_tags);
io_bases=(APTR)GetTagData(PCCARD_IOWinBases,NULL,tuple_tags);
if(io_bases==NULL)
success=FALSE;
}
if(success)
{
io_lengths=(APTR)GetTagData(PCCARD_IOWinLengths,NULL,tuple_tags);
window_count=GetTagData(PCCARD_IOWinCount,0,tuple_tags);
for(i=0;(i<window_count)&&(io_base==0);i++)
if(io_lengths[i]==16)
io_base=io_bases[i];
}
PCCard_FreeTupleInfo(tuple_tags);
/* Configure card */
if(success)
{
card_map=GetCardMap();
unit->config_base=card_map->cmm_AttributeMemory+config_base_offset;
unit->io_base=card_map->cmm_IOMemory+io_base;
unit->config_base[PCCARD_REG_COR]=config_value;
unit->config_base[PCCARD_REG_CCSR]|=PCCARD_REG_CCSRF_AUDIOENABLE;
InitialiseAdapter(unit,base);
unit->flags|=UNITF_HAVEADAPTER;
}
return success;
}
/****i* 3c589.device/InitialiseAdapter *************************************
*
* NAME
* InitialiseAdapter -- .
*
* SYNOPSIS
* InitialiseAdapter(unit)
*
* VOID InitialiseAdapter(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID InitialiseAdapter(struct DevUnit *unit,struct DevBase *base)
{
volatile UBYTE *io_base;
UBYTE *p,i;
UWORD address_part,config,link,media,new_media,medium,media_status;
/* Select IO addresses and interrupt */
io_base=unit->io_base;
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0);
LEWordOut(io_base+EL3REG_RESCONFIG,0x3f00);
/* Get default MAC address */
p=unit->default_address;
for(i=0;i<ADDRESS_SIZE/2;i++)
{
address_part=ReadEEPROM(io_base,EL3EEPROM_ALTADDRESS0+i);
*p++=address_part>>8;
*p++=address_part&0xff;
}
/* Get available transceivers */
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0);
media=LEWordIn(io_base+EL3REG_CONFIG);
/* Get transceivers with an active link */
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|4);
link=0;
media_status=LEWordIn(io_base+EL3REG_MEDIA);
if((media_status&EL3REG_MEDIAF_BEAT)!=0)
link|=EL3REG_CONFIGF_HASTP;
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0);
new_media=media&link;
if((new_media)!=0)
media=new_media;
else
{
/* Get transceiver choice from EEPROM */
config=ReadEEPROM(io_base,EL3EEPROM_ADDRCONFIG)&
(EL3REG_ADDRCONFIG_XCVRMASK|EL3REG_ADDRCONFIGF_AUTOSELECT);
if(config=EL3REG_ADDRCONFIG_XCVRTP)
new_media=EL3REG_CONFIGF_HASTP;
else if(config=EL3REG_ADDRCONFIG_XCVRAUI)
new_media=EL3REG_CONFIGF_HASAUI;
else if(config=EL3REG_ADDRCONFIG_XCVRCOAX)
new_media=EL3REG_CONFIGF_HASCOAX;
else
new_media=EL3REG_CONFIGF_HASTP|EL3REG_CONFIGF_HASCOAX|
EL3REG_CONFIGF_HASAUI;
new_media&=media;
if(new_media!=0)
media=new_media;
}
/* Prioritised choice from remaining transceivers */
if((media&EL3REG_CONFIGF_HASTP)!=0)
medium=EL3REG_ADDRCONFIG_XCVRTP;
else if((media&EL3REG_CONFIGF_HASCOAX)!=0)
medium=EL3REG_ADDRCONFIG_XCVRCOAX;
else
medium=EL3REG_ADDRCONFIG_XCVRAUI;
unit->transceiver=medium;
return;
}
/****i* 3c589.device/ConfigureAdapter **************************************
*
* NAME
* ConfigureAdapter -- .
*
* SYNOPSIS
* ConfigureAdapter(unit)
*
* VOID ConfigureAdapter(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
VOID ConfigureAdapter(struct DevUnit *unit,struct DevBase *base)
{
volatile UBYTE *io_base;
UBYTE i;
/* Set MAC address */
io_base=unit->io_base;
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|2);
for(i=0;i<ADDRESS_SIZE;i++)
ByteOut(io_base+EL3REG_ADDRESS0+i,unit->address[i]);
/* Decide on promiscuous mode */
if((unit->flags&UNITF_PROM)!=0)
unit->rx_filter_cmd|=EL3CMD_SETRXFILTERF_PROM;
/* Select chosen transceiver */
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0);
LEWordOut(io_base+EL3REG_ADDRCONFIG,unit->transceiver);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|1);
/* Go online */
GoOnline(unit,base);
/* Return */
return;
}
/****i* 3c589.device/GoOnline **********************************************
*
* NAME
* GoOnline -- .
*
* SYNOPSIS
* GoOnline(unit)
*
* VOID GoOnline(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
VOID GoOnline(struct DevUnit *unit,struct DevBase *base)
{
volatile UBYTE *io_base;
UWORD transceiver;
/* Choose interrupts */
unit->flags|=UNITF_ONLINE;
io_base=unit->io_base;
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETINTMASK|INT_MASK);
LEWordOut(io_base+EL3REG_COMMAND,(EL3CMD_SETZEROMASK)|0xff);
/* Enable the transceiver */
transceiver=unit->transceiver;
if(transceiver==EL3REG_ADDRCONFIG_XCVRTP)
{
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|4);
LEWordOut(io_base+EL3REG_MEDIA,
EL3REG_MEDIAF_BEATENABLE|EL3REG_MEDIAF_JABBERENABLE);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|1);
}
else if(transceiver==EL3REG_ADDRCONFIG_XCVRCOAX)
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_STARTCOAX|0);
LEWordOut(io_base+EL3REG_COMMAND,unit->rx_filter_cmd);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_RXENABLE);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXENABLE);
/* Record start time and report Online event */
GetSysTime(&unit->stats.LastStart);
ReportEvents(unit,S2EVENT_ONLINE,base);
return;
}
/****i* 3c589.device/GoOffline *********************************************
*
* NAME
* GoOffline -- .
*
* SYNOPSIS
* GoOffline(unit)
*
* VOID GoOffline(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
VOID GoOffline(struct DevUnit *unit,struct DevBase *base)
{
volatile UBYTE *io_base;
io_base=unit->io_base;
unit->flags&=~UNITF_ONLINE;
if((unit->flags&UNITF_HAVEADAPTER)!=0)
{
/* Stop interrupts */
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETINTMASK|0);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_ACKINT|EL3INTF_ANY);
/* Stop transmission and reception */
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_RXDISABLE);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXDISABLE);
/* Turn off TP functions */
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|4);
LEWordOut(io_base+EL3REG_MEDIA,0);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|1);
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_STOPCOAX|0);
}
/* Flush pending read and write requests */
FlushUnit(unit,WRITE_QUEUE,S2ERR_OUTOFSERVICE,base);
/* Report Offline event and return */
ReportEvents(unit,S2EVENT_OFFLINE,base);
return;
}
/****i* 3c589.device/AddMulticastRange *************************************
*
* NAME
* AddMulticastRange -- .
*
* SYNOPSIS
* success = AddMulticastRange(unit,lower_bound,upper_bound)
*
* BOOL AddMulticastRange(struct DevUnit *,UBYTE *,UBYTE *);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
BOOL AddMulticastRange(struct DevUnit *unit,UBYTE *lower_bound,
UBYTE *upper_bound,struct DevBase *base)
{
struct AddressRange *range;
ULONG lower_bound_left,upper_bound_left;
UWORD lower_bound_right,upper_bound_right;
lower_bound_left=BELong(*((ULONG *)lower_bound));
lower_bound_right=BEWord(*((UWORD *)(lower_bound+4)));
upper_bound_left=BELong(*((ULONG *)upper_bound));
upper_bound_right=BEWord(*((UWORD *)(upper_bound+4)));
range=FindMulticastRange(unit,lower_bound_left,lower_bound_right,
upper_bound_left,upper_bound_right,base);
if(range!=NULL)
range->add_count++;
else
{
range=AllocMem(sizeof(struct AddressRange),MEMF_PUBLIC);
if(range!=NULL)
{
range->lower_bound_left=lower_bound_left;
range->lower_bound_right=lower_bound_right;
range->upper_bound_left=upper_bound_left;
range->upper_bound_right=upper_bound_right;
range->add_count=1;
Disable();
AddTail((APTR)&unit->multicast_ranges,(APTR)range);
Enable();
if(unit->range_count++==0)
{
unit->rx_filter_cmd|=EL3CMD_SETRXFILTERF_MCAST;
LEWordOut(unit->io_base+EL3REG_COMMAND,unit->rx_filter_cmd);
}
}
}
return range!=NULL;
}
/****i* 3c589.device/RemMulticastRange *************************************
*
* NAME
* RemMulticastRange -- .
*
* SYNOPSIS
* found = RemMulticastRange(unit,lower_bound,upper_bound)
*
* BOOL RemMulticastRange(struct DevUnit *,UBYTE *,UBYTE *);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
BOOL RemMulticastRange(struct DevUnit *unit,UBYTE *lower_bound,
UBYTE *upper_bound,struct DevBase *base)
{
struct AddressRange *range;
ULONG lower_bound_left,upper_bound_left;
UWORD lower_bound_right,upper_bound_right;
lower_bound_left=BELong(*((ULONG *)lower_bound));
lower_bound_right=BEWord(*((UWORD *)(lower_bound+4)));
upper_bound_left=BELong(*((ULONG *)upper_bound));
upper_bound_right=BEWord(*((UWORD *)(upper_bound+4)));
range=FindMulticastRange(unit,lower_bound_left,lower_bound_right,
upper_bound_left,upper_bound_right,base);
if(range!=NULL)
{
if(--range->add_count==0)
{
Disable();
Remove((APTR)range);
Enable();
FreeMem(range,sizeof(struct AddressRange));
if(--unit->range_count==0)
{
unit->rx_filter_cmd&=~EL3CMD_SETRXFILTERF_MCAST;
LEWordOut(unit->io_base+EL3REG_COMMAND,unit->rx_filter_cmd);
}
}
}
return range!=NULL;
}
/****i* 3c589.device/FindMulticastRange *************************************
*
* NAME
* FindMulticastRange -- .
*
* SYNOPSIS
* range = FindMulticastRange(unit,lower_bound_left,
* lower_bound_right,upper_bound_left,upper_bound_right)
*
* struct AddressRange *FindMulticastRange(struct DevUnit *,ULONG,
* UWORD,ULONG,UWORD);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
ULONG lower_bound_left,UWORD lower_bound_right,ULONG upper_bound_left,
UWORD upper_bound_right,struct DevBase *base)
{
struct AddressRange *range,*tail;
BOOL found;
range=(APTR)unit->multicast_ranges.mlh_Head;
tail=(APTR)&unit->multicast_ranges.mlh_Tail;
found=FALSE;
while((range!=tail)&&!found)
{
if((lower_bound_left==range->lower_bound_left)&&
(lower_bound_right==range->lower_bound_right)&&
(upper_bound_left==range->upper_bound_left)&&
(upper_bound_right==range->upper_bound_right))
found=TRUE;
else
range=(APTR)range->node.mln_Succ;
}
if(!found)
range=NULL;
return range;
}
/****i* 3c589.device/FindTypeStats *****************************************
*
* NAME
* FindTypeStats -- .
*
* SYNOPSIS
* stats = FindTypeStats(unit,list,
* packet_type)
*
* struct TypeStats *FindTypeStats(struct DevUnit *,struct MinList *,
* ULONG);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
struct TypeStats *FindTypeStats(struct DevUnit *unit,struct MinList *list,
ULONG packet_type,struct DevBase *base)
{
struct TypeStats *stats,*tail;
BOOL found;
stats=(APTR)list->mlh_Head;
tail=(APTR)&list->mlh_Tail;
found=FALSE;
while((stats!=tail)&&!found)
{
if(stats->packet_type==packet_type)
found=TRUE;
else
stats=(APTR)stats->node.mln_Succ;
}
if(!found)
stats=NULL;
return stats;
}
/****i* 3c589.device/FlushUnit *********************************************
*
* NAME
* FlushUnit -- .
*
* SYNOPSIS
* FlushUnit(unit)
*
* VOID FlushUnit(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
VOID FlushUnit(struct DevUnit *unit,UBYTE last_queue,BYTE error,
struct DevBase *base)
{
struct IORequest *request;
UBYTE i;
struct Opener *opener,*tail;
/* Abort queued requests */
for(i=0;i<=last_queue;i++)
{
while((request=(APTR)GetMsg(unit->request_ports[i]))!=NULL)
{
request->io_Error=IOERR_ABORTED;
ReplyMsg((APTR)request);
}
}
#if 1
opener=(APTR)unit->openers.mlh_Head;
tail=(APTR)&unit->openers.mlh_Tail;
/* Flush every opener's read queue */
while(opener!=tail)
{
while((request=(APTR)GetMsg(&opener->read_port))!=NULL)
{
request->io_Error=error;
ReplyMsg((APTR)request);
}
opener=(APTR)opener->node.mln_Succ;
}
#else
opener=request->ios2_BufferManagement;
while((request=(APTR)GetMsg(&opener->read_port))!=NULL)
{
request->io_Error=IOERR_ABORTED;
ReplyMsg((APTR)request);
}
#endif
/* Return */
return;
}
/****i* 3c589.device/CardRemovedInt ****************************************
*
* NAME
* CardRemovedInt -- .
*
* SYNOPSIS
* CardRemovedInt(unit)
*
* VOID CardRemovedInt(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID CardRemovedInt(struct DevUnit *unit REG("a1"))
{
struct DevBase *base;
/* Record loss of card and get our task to call ReleaseCard() */
base=unit->device;
unit->flags&=~(UNITF_HAVEADAPTER|UNITF_HAVECARD|UNITF_ONLINE);
Signal(unit->task,unit->card_removed_signal);
return;
}
/****i* 3c589.device/CardInsertedInt ***************************************
*
* NAME
* CardInsertedInt -- .
*
* SYNOPSIS
* CardInsertedInt(unit)
*
* VOID CardInsertedInt(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID CardInsertedInt(struct DevUnit *unit REG("a1"))
{
struct DevBase *base;
base=unit->device;
Signal(unit->task,unit->card_inserted_signal);
return;
}
/****i* 3c589.device/CardStatusInt *****************************************
*
* NAME
* CardStatusInt -- .
*
* SYNOPSIS
* mask = CardStatusInt(mask,unit)
*
* UBYTE CardStatusInt(UBYTE mask,struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* mask
* unit
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static UBYTE CardStatusInt(UBYTE mask REG("d0"),
struct DevUnit *unit REG("a1"))
{
struct DevBase *base;
volatile UBYTE *io_base;
UWORD ints;
base=unit->device;
if((mask&CARD_STATUSF_IRQ)!=0)
{
io_base=unit->io_base;
ints=LEWordIn(io_base+EL3REG_STATUS);
if((ints&EL3INTF_ANY)!=0) /* ??? */
{
/* Handle interrupts */
if((ints&EL3INTF_RXCOMPLETE)!=0)
{
LEWordOut(io_base+EL3REG_COMMAND,
EL3CMD_SETINTMASK|(INT_MASK&~EL3INTF_RXCOMPLETE));
Cause(&unit->rx_int);
}
if((ints&EL3INTF_TXAVAIL)!=0)
{
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_ACKINT|
EL3INTF_TXAVAIL);
Cause(&unit->tx_int);
}
if((ints&EL3INTF_TXCOMPLETE)!=0)
TxError(unit,base);
if((ints&EL3INTF_FAILURE)!=0)
*((UWORD *)8)=0x9999;
/* Acknowledge interrupt request */
LEWordOut(io_base+EL3REG_COMMAND,
EL3CMD_ACKINT|EL3INTF_ANY);
}
/* Work around gayle interrupt bug */
*((volatile UBYTE *)0xda9000)=(mask^0x2c)|0xc0;
mask=0;
}
return mask;
}
/****i* 3c589.device/RxInt *************************************************
*
* NAME
* RxInt -- .
*
* SYNOPSIS
* RxInt(unit)
*
* VOID RxInt(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit - A unit of this device.
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID RxInt(struct DevUnit *unit REG("a1"))
{
volatile UBYTE *io_base;
UWORD rx_status,packet_size;
struct DevBase *base;
BOOL is_orphan=TRUE,all_read,accepted;
ULONG packet_type,*p,*end;
UBYTE *buffer;
struct IOSana2Req *request,*request_tail;
struct Opener *opener,*opener_tail;
struct TypeStats *tracker;
base=unit->device;
io_base=unit->io_base;
while(((rx_status=LEWordIn(io_base+EL3REG_RXSTATUS))
&EL3REG_RXSTATUSF_INCOMPLETE)==0)
{
if((rx_status&EL3REG_RXSTATUSF_ERROR)==0)
{
/* Read packet header */
all_read=FALSE;
packet_size=rx_status&EL3REG_RXSTATUS_SIZEMASK;
p=(ULONG *)buffer=unit->rx_buffer;
end=(ULONG *)(buffer+PACKET_DATA);
while(p<end)
*p++=LongIn(io_base+EL3REG_DATA0);
if(AddressFilter(unit,buffer+PACKET_DEST,base))
{
packet_type=BEWord(*((UWORD *)(buffer+PACKET_TYPE)));
opener=(APTR)unit->openers.mlh_Head;
opener_tail=(APTR)&unit->openers.mlh_Tail;
/* Offer packet to every opener */
while(opener!=opener_tail)
{
request=(APTR)opener->read_port.mp_MsgList.lh_Head;
request_tail=(APTR)&opener->read_port.mp_MsgList.lh_Tail;
accepted=FALSE;
/* Offer packet to each request until it's accepted */
while((request!=request_tail)&&!accepted)
{
if(request->ios2_PacketType==packet_type)
{
CopyPacket(unit,request,packet_size,packet_type,
all_read,base);
accepted=TRUE;
}
request=
(APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
}
if(accepted)
{
is_orphan=FALSE;
all_read=TRUE;
}
opener=(APTR)opener->node.mln_Succ;
}
/* If packet was unwanted, give it to S2_READORPHAN request */
if(is_orphan)
{
unit->stats.UnknownTypesReceived++;
if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
{
CopyPacket(unit,
(APTR)unit->request_ports[ADOPT_QUEUE]->
mp_MsgList.lh_Head,packet_size,packet_type,all_read,
base);
is_orphan=FALSE;
all_read=TRUE;
}
}
/* Update remaining statistics */
unit->stats.PacketsReceived++;
tracker=
FindTypeStats(unit,&unit->type_trackers,packet_type,base);
if(tracker!=NULL)
{
tracker->stats.PacketsReceived++;
tracker->stats.BytesReceived+=packet_size;
}
}
}
else
{
unit->stats.BadData++;
ReportEvents(unit,S2EVENT_ERROR|S2EVENT_HARDWARE|S2EVENT_RX,base);
}
/* Discard packet */
Disable();
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_RXDISCARD);
while((LEWordIn(io_base+EL3REG_STATUS)&
EL3REG_STATUSF_CMDINPROGRESS)!=0);
Enable();
}
/* Return */
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETINTMASK|INT_MASK);
return;
}
/****i* 3c589.device/CopyPacket ********************************************
*
* NAME
* CopyPacket -- .
*
* SYNOPSIS
* CopyPacket(unit,request,packet_size,packet_type,
* all_read)
*
* VOID CopyPacket(struct DevUnit *,struct IOSana2Req *,UWORD,UWORD,
* BOOL);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID CopyPacket(struct DevUnit *unit,struct IOSana2Req *request,
UWORD packet_size,UWORD packet_type,BOOL all_read,struct DevBase *base)
{
volatile UBYTE *io_base;
struct Opener *opener;
UBYTE *buffer;
BOOL filtered=FALSE;
ULONG *p,*end;
/* Set packet length */
io_base=unit->io_base;
/* Set multicast and broadcast flags */
buffer=unit->rx_buffer;
request->ios2_Req.io_Flags&=~(SANA2IOB_BCAST|SANA2IOB_MCAST);
if((*((ULONG *)(buffer+PACKET_DEST))==0xffffffff)&&
(*((UWORD *)(buffer+PACKET_DEST+4))==0xffff))
request->ios2_Req.io_Flags|=SANA2IOB_BCAST;
else if((buffer[PACKET_DEST]&0x1)!=0)
request->ios2_Req.io_Flags|=SANA2IOB_MCAST;
/* Set source and destination addresses and packet type */
CopyMem(buffer+PACKET_SOURCE,request->ios2_SrcAddr,ADDRESS_SIZE);
CopyMem(buffer+PACKET_DEST,request->ios2_DstAddr,ADDRESS_SIZE);
request->ios2_PacketType=packet_type;
/* Read rest of packet */
if(!all_read)
{
p=(ULONG *)(buffer+((PACKET_DATA+3)&~3));
end=(ULONG *)(buffer+packet_size);
while(p<end)
*p++=LongIn(io_base+EL3REG_DATA0);
}
if((request->ios2_Req.io_Flags&SANA2IOF_RAW)==0)
{
packet_size-=PACKET_DATA;
buffer+=PACKET_DATA;
}
#ifdef USE_HACKS
else
packet_size+=4; /* Needed for Shapeshifter & Fusion */
#endif
request->ios2_DataLength=packet_size;
/* Filter packet */
opener=request->ios2_BufferManagement;
if((request->ios2_Req.io_Command==CMD_READ)&&
(opener->filter_hook!=NULL))
if(!CallHookPkt(opener->filter_hook,request,buffer))
filtered=TRUE;
if(!filtered)
{
/* Copy packet into opener's buffer and reply packet */
if(!opener->rx_function(request->ios2_Data,buffer,packet_size))
{
request->ios2_Req.io_Error=S2ERR_NO_RESOURCES;
request->ios2_WireError=S2WERR_BUFF_ERROR;
ReportEvents(unit,
S2EVENT_ERROR|S2EVENT_SOFTWARE|S2EVENT_BUFF|S2EVENT_RX,base);
}
Remove((APTR)request);
ReplyMsg((APTR)request);
}
return;
}
/****i* 3c589.device/AddressFilter *****************************************
*
* NAME
* AddressFilter -- .
*
* SYNOPSIS
* accept = AddressFilter(unit,address)
*
* BOOL AddressFilter(struct DevUnit *,UBYTE *);
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static BOOL AddressFilter(struct DevUnit *unit,UBYTE *address,
struct DevBase *base)
{
struct AddressRange *range,*tail;
BOOL accept=TRUE;
ULONG address_left;
UWORD address_right;
/* Check whether address is unicast/broadcast or multicast */
address_left=BELong(*((ULONG *)address));
address_right=BEWord(*((UWORD *)(address+4)));
if(((address_left&0x01000000)!=0)&&
!((address_left==0xffffffff)&&(address_right==0xffff)))
{
/* Check if this multicast address is wanted */
range=(APTR)unit->multicast_ranges.mlh_Head;
tail=(APTR)&unit->multicast_ranges.mlh_Tail;
accept=FALSE;
while((range!=tail)&&!accept)
{
if(((address_left>range->lower_bound_left)||
(address_left==range->lower_bound_left)&&
(address_right>=range->lower_bound_right))&&
((address_left<range->upper_bound_left)||
(address_left==range->upper_bound_left)&&
(address_right<=range->upper_bound_right)))
accept=TRUE;
range=(APTR)range->node.mln_Succ;
}
if(!accept)
unit->special_stats[S2SS_ETHERNET_BADMULTICAST&0xffff]++;
}
return accept;
}
/****i* 3c589.device/TxInt *************************************************
*
* NAME
* TxInt -- .
*
* SYNOPSIS
* TxInt(unit)
*
* VOID TxInt(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit - A unit of this device.
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID TxInt(struct DevUnit *unit REG("a1"))
{
volatile UBYTE *io_base;
UWORD packet_size,data_size,send_size;
struct DevBase *base;
struct IOSana2Req *request;
BOOL proceed=TRUE;
struct Opener *opener;
ULONG *buffer,*end,wire_error;
ULONG *(*dma_tx_function)(APTR REG("a0"));
BYTE error;
struct MsgPort *port;
struct TypeStats *tracker;
base=unit->device;
io_base=unit->io_base;
port=unit->request_ports[WRITE_QUEUE];
while(proceed&&(!IsMsgPortEmpty(port)))
{
error=0;
request=(APTR)port->mp_MsgList.lh_Head;
data_size=packet_size=request->ios2_DataLength;
if((request->ios2_Req.io_Flags&SANA2IOF_RAW)==0)
packet_size+=PACKET_DATA;
if(LEWordIn(io_base+EL3REG_TXSPACE)>PREAMBLE_SIZE+packet_size)
{
/* Write packet preamble */
LELongOut(io_base+EL3REG_DATA0,packet_size);
/* Write packet header */
send_size=(packet_size+3)&(~0x3);
if((request->ios2_Req.io_Flags&SANA2IOF_RAW)==0)
{
LongOut(io_base+EL3REG_DATA0,*((ULONG *)request->ios2_DstAddr));
WordOut(io_base+EL3REG_DATA0,
*((UWORD *)(request->ios2_DstAddr+4)));
WordOut(io_base+EL3REG_DATA0,*((UWORD *)unit->address));
LongOut(io_base+EL3REG_DATA0,*((ULONG *)(unit->address+2)));
BEWordOut(io_base+EL3REG_DATA0,request->ios2_PacketType);
send_size-=PACKET_DATA;
}
/* Get packet data */
opener=(APTR)request->ios2_BufferManagement;
dma_tx_function=opener->dma_tx_function;
if(dma_tx_function!=NULL)
buffer=dma_tx_function(request->ios2_Data);
else
buffer=NULL;
if(buffer==NULL)
{
buffer=(ULONG *)unit->tx_buffer;
if(!opener->tx_function(buffer,request->ios2_Data,data_size))
{
error=S2ERR_NO_RESOURCES;
wire_error=S2WERR_BUFF_ERROR;
ReportEvents(unit,
S2EVENT_ERROR|S2EVENT_SOFTWARE|S2EVENT_BUFF|S2EVENT_TX,
base);
}
}
/* Write packet data */
if(error==0)
{
end=buffer+(send_size>>2);
while(buffer<end)
LongOut(io_base+EL3REG_DATA0,*buffer++);
if((send_size&0x3)!=0)
WordOut(io_base+EL3REG_DATA0,*((UWORD *)buffer));
}
/* Reply packet */
request->ios2_Req.io_Error=error;
request->ios2_WireError=wire_error;
Remove((APTR)request);
ReplyMsg((APTR)request);
/* Update statistics */
if(error==0)
{
unit->stats.PacketsSent++;
tracker=FindTypeStats(unit,&unit->type_trackers,
request->ios2_PacketType,base);
if(tracker!=NULL)
{
tracker->stats.PacketsSent++;
tracker->stats.BytesSent+=packet_size;
}
}
}
else
proceed=FALSE;
}
if(proceed)
unit->request_ports[WRITE_QUEUE]->mp_Flags=PA_SOFTINT;
else
{
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETTXTHRESH
|(PREAMBLE_SIZE+packet_size));
unit->request_ports[WRITE_QUEUE]->mp_Flags=PA_IGNORE;
}
return;
}
/****i* 3c589.device/TxError ***********************************************
*
* NAME
* TxError -- .
*
* SYNOPSIS
* TxError(unit)
*
* VOID TxError(struct DevUnit *);
*
* FUNCTION
*
* INPUTS
* unit - A unit of this device.
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
VOID TxError(struct DevUnit *unit,struct DevBase *base)
{
volatile UBYTE *io_base;
UBYTE tx_status,flags;
base=unit->device;
io_base=unit->io_base;
/* Gather all errors */
while(((tx_status=ByteIn(io_base+EL3REG_TXSTATUS))
&EL3REG_TXSTATUSF_COMPLETE)!=0)
{
flags|=tx_status;
ByteOut(io_base+EL3REG_TXSTATUS,0);
}
/* Restart transmitter if necessary */
if((flags&EL3REG_TXSTATUSF_JABBER)!=0)
{
Disable();
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXRESET);
while((LEWordIn(io_base+EL3REG_STATUS)&
EL3REG_STATUSF_CMDINPROGRESS)!=0);
Enable();
}
if((flags&(EL3REG_TXSTATUSF_JABBER|EL3REG_TXSTATUSF_OVERFLOW))!=0)
LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXENABLE);
/* Report the error(s) */
ReportEvents(unit,S2EVENT_ERROR|S2EVENT_HARDWARE|S2EVENT_TX,base);
return;
}
/****i* 3c589.device/ReportEvents ******************************************
*
* NAME
* ReportEvents -- .
*
* SYNOPSIS
* ReportEvents(unit,events)
*
* VOID ReportEvents(struct DevUnit *,ULONG);
*
* FUNCTION
*
* INPUTS
* unit - A unit of this device.
* events - A mask of events to report.
*
* RESULT
* None.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID ReportEvents(struct DevUnit *unit,ULONG events,
struct DevBase *base)
{
struct IOSana2Req *request,*tail,*next_request;
struct List *list;
list=&unit->request_ports[EVENT_QUEUE]->mp_MsgList;
next_request=(APTR)list->lh_Head;
tail=(APTR)&list->lh_Tail;
Disable();
while(next_request!=tail)
{
request=next_request;
next_request=(APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
if((request->ios2_WireError&events)!=0)
{
request->ios2_WireError=events;
Remove((APTR)request);
ReplyMsg((APTR)request);
}
}
Enable();
return;
}
/****i* 3c589.device/UnitTask **********************************************
*
* NAME
* UnitTask -- .
*
* SYNOPSIS
* UnitTask()
*
* VOID UnitTask();
*
* FUNCTION
*
* INPUTS
*
* RESULT
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static VOID UnitTask()
{
struct Task *task;
struct IORequest *request;
struct DevUnit *unit;
struct DevBase *base;
struct MsgPort *general_port;
ULONG signals,wait_signals,card_removed_signal,card_inserted_signal,
general_port_signal;
/* Get parameters */
task=AbsExecBase->ThisTask;
unit=task->tc_UserData;
base=unit->device;
/* Activate general request port */
general_port=unit->request_ports[GENERAL_QUEUE];
general_port->mp_SigTask=task;
general_port->mp_SigBit=AllocSignal(-1);
general_port_signal=1<<general_port->mp_SigBit;
general_port->mp_Flags=PA_SIGNAL;
/* Allocate a signal for notification of card removal */
card_removed_signal=unit->card_removed_signal=1<<AllocSignal(-1);
card_inserted_signal=unit->card_inserted_signal=1<<AllocSignal(-1);
wait_signals=(1<<general_port->mp_SigBit)|card_removed_signal
|card_inserted_signal;
/* Tell ourselves to check port for old messages */
Signal(task,general_port_signal);
/* Infinite loop to service requests and signals */
while(TRUE)
{
signals=Wait(wait_signals);
if((signals&card_inserted_signal)!=0)
{
if(InitialiseCard(unit,base))
{
unit->flags|=UNITF_HAVECARD;
if((unit->flags&UNITF_CONFIGURED)!=0)
ConfigureAdapter(unit,base);
}
else
ReleaseCard(unit->card_handle,0);
}
if((signals&card_removed_signal)!=0)
{
ReleaseCard(unit->card_handle,0);
GoOffline(unit,base);
}
if((signals&general_port_signal)!=0)
{
while((request=(APTR)GetMsg(general_port))!=NULL)
{
/* Service the request as soon as the unit is free */
ObtainSemaphore(&unit->access_lock);
ServiceRequest((APTR)request,base);
}
}
}
}
/****i* 3c589.device/ReadEEPROM ********************************************
*
* NAME
* ReadEEPROM -- .
*
* SYNOPSIS
* value = ReadEEPROM(io_base,index)
*
* UWORD ReadEEPROM(UBYTE *,UWORD);
*
* FUNCTION
*
* INPUTS
* io_base - Base of adapter's register window.
* index - Offset within EEPROM.
*
* RESULT
* value - Contents of specified EEPROM location.
*
* EXAMPLE
*
* NOTES
*
* BUGS
*
* SEE ALSO
*
****************************************************************************
*
*/
static UWORD ReadEEPROM(volatile UBYTE *io_base,UWORD index)
{
LEWordOut(io_base+EL3REG_EEPROMCMD,EL3ECMD_READ|index);
while((LEWordIn(io_base+EL3REG_EEPROMCMD)&EL3REG_EEPROMCMDF_BUSY)
!=0);
return LEWordIn(io_base+EL3REG_EEPROMDATA);
}
static UWORD LEWordIn(volatile UBYTE *address)
{
UWORD datum;
datum=*((volatile UWORD *)(address));
return (datum<<8)|(datum>>8);
}